package com.beta.cat.config;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.redisson.client.codec.StringCodec;
import org.redisson.config.Config;
import org.springframework.core.env.Environment;

@Slf4j
public class BaseRedisConfig {

    public static Config initConfig(Environment environment, String basePrefix) {
        String deployMode = environment.getProperty(basePrefix + ".deployMode", "").trim();
        if (StringUtils.isBlank(deployMode)) {
            return null;
        }
        log.info("使用{}模式连接redis...", deployMode);
        Config config = new Config();
        //默认编码 JsonJacksonCodec
        config.setCodec(new StringCodec());
        if ("Single".equals(deployMode)) {
            /**
             * 单节点模式
             *
             * spring.redis.user.deployMode=
             * spring.redis.user.address=
             * spring.redis.user.password=
             * spring.redis.user.connectionPoolSize=500
             * spring.redis.user.idleConnectionTimeout=10000
             * spring.redis.user.timeout=3000
             * spring.redis.user.connectTimeout=30000
             */
            config.useSingleServer()
                    .setAddress(environment.getProperty(basePrefix + ".address").trim())
                    //优化密码为 空的场景
                    //.setPassword(environment.getProperty(basePrefix + ".password").trim())

                    //设置连接池最大连接数：500
                    .setConnectionPoolSize(Integer.parseInt(environment.getProperty(basePrefix + ".connectionPoolSize").trim()))

                    //当连接池的连接数 > 最小空闲连接数，同时，有连接空闲时间 > 该值，那么该连接将自动关闭。单位：毫秒
                    .setIdleConnectionTimeout(Integer.parseInt(environment.getProperty(basePrefix + ".idleConnectionTimeout").trim()))
                    //等待节点回复命令的时间。从命令发送成功时开始计时。
                    .setTimeout(Integer.parseInt(environment.getProperty(basePrefix + ".timeout").trim()))
                    //与节点建立连接时的等待超时时间。单位：毫秒
                    .setConnectTimeout(Integer.parseInt(environment.getProperty(basePrefix + ".connectTimeout").trim()))

                    .setRetryAttempts(3)
                    .setRetryInterval(1000)
                    .setDnsMonitoringInterval(-1)
                    .setPingConnectionInterval(10000)
                    .setDatabase(Integer.parseInt(environment.getProperty(basePrefix + ".database", "15").trim()));

            //设置密码 兼容密码不存在场景
            String password = environment.getProperty(basePrefix + ".password");
            if (StringUtils.isNotBlank(password)) {
                config.useSingleServer().setPassword(password.trim());
            }

        } else if ("MasterSlave".equals(deployMode)) {
            /**
             * 主从模式
             *
             * spring.redis.user.deployMode=
             * spring.redis.user.masterAddress=
             * spring.redis.user.slaveAddress=
             * spring.redis.user.password=
             * spring.redis.user.masterConnectionPoolSize=500
             * spring.redis.user.slaveConnectionPoolSize=500
             * spring.redis.user.idleConnectionTimeout=10000
             * spring.redis.user.timeout=3000
             * spring.redis.user.connectTimeout=30000
             */
            config.useMasterSlaveServers()
                    //设置 主 节点
                    .setMasterAddress(environment.getProperty(basePrefix + ".masterAddress").trim())
                    //设置 从 节点
                    .addSlaveAddress(environment.getProperty(basePrefix + ".masterAddress").trim().split(","))
                    //优化密码为 空的场景
                    //.setPassword(environment.getProperty(basePrefix + ".password").trim())
                    //设置 master 节点连接池最大连接数：500
                    .setMasterConnectionPoolSize(Integer.parseInt(environment.getProperty(basePrefix + ".masterConnectionPoolSize").trim()))
                    //设置 slave 节点连接池最大连接数：500
                    .setSlaveConnectionPoolSize(Integer.parseInt(environment.getProperty(basePrefix + ".slaveConnectionPoolSize").trim()))

                    //当连接池的连接数 > 最小空闲连接数，同时，有连接空闲时间 > 该值，那么该连接将自动关闭。单位：毫秒
                    .setIdleConnectionTimeout(Integer.parseInt(environment.getProperty(basePrefix + ".idleConnectionTimeout").trim()))
                    //等待节点回复命令的时间。从命令发送成功时开始计时。
                    .setTimeout(Integer.parseInt(environment.getProperty(basePrefix + ".timeout").trim()))
                    //与节点建立连接时的等待超时时间。单位：毫秒
                    .setConnectTimeout(Integer.parseInt(environment.getProperty(basePrefix + ".connectTimeout").trim()))
                    .setDatabase(Integer.parseInt(environment.getProperty(basePrefix + ".database", "15").trim()));

            //设置密码 兼容密码不存在场景
            String password = environment.getProperty(basePrefix + ".password");
            if (StringUtils.isNotBlank(password)) {
                config.useMasterSlaveServers().setPassword(password.trim());
            }


        } else if ("Sentinel".equals(deployMode)) {
            /**
             * 哨兵模式
             *
             * spring.redis.user.deployMode=
             * spring.redis.user.masterName=
             * spring.redis.user.sentinelAddress=
             * spring.redis.user.password=
             * spring.redis.user.masterConnectionPoolSize=500
             * spring.redis.user.slaveConnectionPoolSize=500
             * spring.redis.user.idleConnectionTimeout=10000
             * spring.redis.user.timeout=3000
             * spring.redis.user.connectTimeout=30000
             */
            config.useSentinelServers()
                    // 在Redisson启动期间启用sentinels列表检查
                    .setCheckSentinelsList(BooleanUtils.toBoolean(environment.getProperty(basePrefix + ".checkSentinelsList", "true").trim()))
                    //设置 sentinel.conf 配置里的 sentinel 别名
                    .setMasterName(environment.getProperty(basePrefix + ".masterName").trim())
                    //设置 sentinel 节点的服务IP和端口，考虑采用的是 Paxos 拜占庭协议，节点数至少 3 个以上
                    .addSentinelAddress(environment.getProperty(basePrefix + ".sentinelAddress").trim().split(","))
                    //.setPassword(environment.getProperty(basePrefix + ".password").trim())
                    //设置 master 节点连接池最大连接数：500
                    .setMasterConnectionPoolSize(Integer.parseInt(environment.getProperty(basePrefix + ".masterConnectionPoolSize").trim()))
                    //设置 slave 节点连接池最大连接数：500
                    .setSlaveConnectionPoolSize(Integer.parseInt(environment.getProperty(basePrefix + ".slaveConnectionPoolSize").trim()))

                    //当连接池的连接数 > 最小空闲连接数，同时，有连接空闲时间 > 该值，那么该连接将自动关闭。单位：毫秒
                    .setIdleConnectionTimeout(Integer.parseInt(environment.getProperty(basePrefix + ".idleConnectionTimeout").trim()))
                    //等待节点回复命令的时间。从命令发送成功时开始计时。
                    .setTimeout(Integer.parseInt(environment.getProperty(basePrefix + ".timeout").trim()))
                    //与节点建立连接时的等待超时时间。单位：毫秒
                    .setConnectTimeout(Integer.parseInt(environment.getProperty(basePrefix + ".connectTimeout").trim()))
                    .setDatabase(Integer.parseInt(environment.getProperty(basePrefix + ".database", "15").trim()));

            //设置密码 兼容密码不存在场景
            String password = environment.getProperty(basePrefix + ".password");
            if (StringUtils.isNotBlank(password)) {
                config.useSentinelServers().setPassword(password.trim());
            }

        } else if ("Cluster".equals(deployMode)) {
            /**
             * 集群模式
             *
             * spring.redis.user.deployMode=
             * spring.redis.user.scanInterval=
             * spring.redis.user.nodeAddress=
             * spring.redis.user.password=
             * spring.redis.user.masterConnectionPoolSize=500
             * spring.redis.user.slaveConnectionPoolSize=500
             * spring.redis.user.idleConnectionTimeout=10000
             * spring.redis.user.timeout=3000
             * spring.redis.user.connectTimeout=30000
             */
            config.useClusterServers()
                    //集群状态扫描间隔时间。单位是毫秒
                    .setScanInterval(Integer.parseInt(environment.getProperty(basePrefix + ".scanInterval").trim()))
                    //集群配置，至少 3主3从 的配置
                    .addNodeAddress(environment.getProperty(basePrefix + ".sentinelAddress").trim().split(","))
                    //.setPassword(environment.getProperty(basePrefix + ".password").trim())

                    //设置 master 节点连接池最大连接数：500
                    .setMasterConnectionPoolSize(Integer.parseInt(environment.getProperty(basePrefix + ".masterConnectionPoolSize").trim()))
                    //设置 slave 节点连接池最大连接数：500
                    .setSlaveConnectionPoolSize(Integer.parseInt(environment.getProperty(basePrefix + ".slaveConnectionPoolSize").trim()))
                    //当连接池的连接数 > 最小空闲连接数，同时，有连接空闲时间 > 该值，那么该连接将自动关闭。单位：毫秒
                    .setIdleConnectionTimeout(Integer.parseInt(environment.getProperty(basePrefix + ".idleConnectionTimeout").trim()))
                    //等待节点回复命令的时间。从命令发送成功时开始计时。
                    .setTimeout(Integer.parseInt(environment.getProperty(basePrefix + ".timeout").trim()))
                    //与节点建立连接时的等待超时时间。单位：毫秒
                    .setConnectTimeout(Integer.parseInt(environment.getProperty(basePrefix + ".connectTimeout").trim()))
            ;

            //设置密码 兼容密码不存在场景
            String password = environment.getProperty(basePrefix + ".password");
            if (StringUtils.isNotBlank(password)) {
                config.useClusterServers().setPassword(password.trim());
            }
        }
        return config;
    }
}
